﻿namespace Mercury.ParticleEngine
{
    using System;

    /// <summary>
    /// Defines an object which can be used to iterate over a circular buffer of meta particles.
    /// </summary>
    public unsafe struct MetaParticleIterator
    {
        private readonly MetaParticle* _buffer;
        private readonly Int32 _size;
        private readonly Int32 _startIndex;
        private readonly Int32 _count;
        private Int32 _currentIteration;

        /// <summary>
        /// A pointer to the first item in the iteration.
        /// </summary>
        public readonly MetaParticle* First;

        /// <summary>
        /// Initializes a new instancer of the <see cref="MetaParticleIterator"/> structure.
        /// </summary>
        /// <param name="buffer">A pointer to the pinned circular buffer to iterate over.</param>
        /// <param name="size">The total number of items in the buffer.</param>
        /// <param name="startIndex">The index of the first active item in the buffer.</param>
        /// <param name="count">The total number of active items in the buffer.</param>
        public MetaParticleIterator(MetaParticle* buffer, Int32 size, Int32 startIndex, Int32 count)
        {
            _buffer     = buffer;
            _size       = size;
            _startIndex = startIndex;
            _count      = count;

            _currentIteration = 0;

            First = buffer + _startIndex;
        }

        /// <summary>
        /// Moves the iteration to the next value.
        /// </summary>
        /// <param name="meta">A double pointer to a meta particle structure which will be updated
        /// to point at the next item in the iteration.</param>
        /// <returns><c>true</c> if the iteration should continue; else <c>false</c>.</returns>
        public Boolean MoveNext(MetaParticle** meta)
        {
            if (++_currentIteration > (_count - 1))
                return false;

            (*meta) = _buffer + ((_startIndex + _currentIteration) % _size);

            return true;
        }

        /// <summary>
        /// Resets the iterator back to the first iteration so that it can be run again from the
        /// beginning.
        /// </summary>
        public void Reset()
        {
            _currentIteration = 0;
        }
    }
}